package com.tinyseed.emcp.api.basicdata.service;

import com.tinyseed.emcp.api.basicdata.domain.Organize;
import com.tinyseed.emcp.api.basicdata.model.OrganizeInputDTO;
import com.tinyseed.emcp.api.basicdata.model.OrganizeOutputDTO;
import com.tinyseed.emcp.api.basicdata.repository.OrganizeRepository;
import com.tinyseed.hmxx.admin.security.utils.SecurityUtils;
import com.tinyseed.hmxx.admin.system.domain.Dept;
import com.tinyseed.hmxx.admin.system.domain.dto.DeptDTO;
import com.tinyseed.hmxx.admin.system.service.DeptService;
import com.tinyseed.hmxx.admin.system.service.mapper.DeptMapper;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;

import javax.persistence.criteria.*;
import java.sql.Time;
import java.sql.Timestamp;
import java.util.*;

@Service
@CacheConfig(cacheNames = "organize")
public class OrganizeServiceImpl implements OrganizeService {

    private final OrganizeRepository organizeRepository;

    private final DeptService deptService;

    @Autowired
    private DeptMapper deptMapper;

    public OrganizeServiceImpl(OrganizeRepository organizeRepository, DeptService deptService) {
        this.organizeRepository = organizeRepository;
        this.deptService = deptService;
    }

    @Override
    public List<OrganizeOutputDTO> getOptionList() {

        return createTree(0L, getList());
    }
    @Override
    @Cacheable(key= "#p0")
    public List<OrganizeOutputDTO> getOptionList(Long id) {
        return createTree(id, getList());
    }

    //查找权限下面的组织结构
    @Override
    public List<OrganizeOutputDTO> findOrganzeBydept(Long deptId){

        List<Organize> out =   organizeRepository.findAll((Root<Organize> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) -> {
            List<Predicate> list = new ArrayList<>();
            Optional.ofNullable(deptId).ifPresent(item->{
                Join<Organize, Dept> dept = root.join("dept", JoinType.LEFT);
                Predicate in = dept.in(item);
                list.add(in);
            });
            Predicate[] p = list.toArray(new Predicate[0]);
            return criteriaBuilder.and(p);
        });
        List<OrganizeOutputDTO> organizeOutputDTOList = new ArrayList<>();
        out.forEach(organize -> {
            OrganizeOutputDTO organizeOutputDTO = new OrganizeOutputDTO();
            BeanUtils.copyProperties(organize, organizeOutputDTO);
            organizeOutputDTOList.add(organizeOutputDTO);
        });
        return organizeOutputDTOList;
    }


    @Override
    public List<OrganizeOutputDTO> getList() {
        List<Organize> list = organizeRepository.findAll();
        List<OrganizeOutputDTO> organizeOutputDTOList = new ArrayList<>();
        list.forEach(organize -> {
            OrganizeOutputDTO organizeOutputDTO = new OrganizeOutputDTO();
            BeanUtils.copyProperties(organize, organizeOutputDTO);
            organizeOutputDTOList.add(organizeOutputDTO);
        });
        return organizeOutputDTOList;
    }

    @Override
    @Cacheable
    public List<OrganizeOutputDTO> getOrganizeIdListByid(Long parentId) {
        List<OrganizeOutputDTO> target = new ArrayList<>();
        return findTree(parentId, getList(), target);
    }

    @Override
    public OrganizeOutputDTO getDataById(Long parentId) {
        Organize organize = organizeRepository.findById(parentId).orElse(new Organize());
        OrganizeOutputDTO organizeOutputDTO = new OrganizeOutputDTO();
        BeanUtils.copyProperties(organize, organizeOutputDTO);
        return organizeOutputDTO;
    }

    public String getOrganizeParent(String name) {
        /**
         * Description 找他爹
         * Version 1.0 
         * Date 2020/3/29 11:07 下午 
         * Author howard
         * @param id
         * @return java.util.List<com.tinyseed.emcp.api.basicdata.model.OrganizeOutputDTO>
         */
        Optional<Organize> organize = organizeRepository.findByOrganizeName(name);

        if (organize.isPresent()) {
            Organize o = organize.get();
            return organizeRepository.findById(o.getParentId()).map(Organize::getOrganizeName).get();
        }
        return "无法归类";

    }

    @Override
    public Integer deleteById(Long id) {
        organizeRepository.deleteById(id);
        organizeRepository.deleteByParentId(id);
        return 1;
    }

    @Override
    public void save(OrganizeInputDTO organizeInputDTO) {
        Organize organize = organizeInputDTO.convertToOrganize();
        if (null == organize) return;
        Timestamp now = new Timestamp(new Date().getTime());
        if (null == organize.getId()) {
            organize.setCreateTime(now);
            organize.setCreator(SecurityUtils.getUsername());
        }
        organize.setModifyTime(now);
        organize.setModifier(SecurityUtils.getUsername());
        organizeRepository.save(organize);
    }

    @Override
    public List<Dept> findDeptByOrganize(Long organizeId) {
        return null;
    }

    @Override
    public void addDept(Long organizeId, List<Long> dept) {
        organizeRepository.findById(organizeId).ifPresent(organize -> {

                    Set<Dept> deptList = new HashSet<>();
                    dept.forEach(id -> {
                        DeptDTO temp = deptService.findById(id);
                        deptList.add(deptMapper.toEntity(temp));
                    });
                    organize.setDept(deptList);
                    organizeRepository.save(organize);
                }
        );


    }

    @Override
    public Organize removeDept(Long deptId) {
        return null;
    }

    /*构建递归树*/
    private List<OrganizeOutputDTO> createTree(Long id, List<OrganizeOutputDTO> list) {
        List<OrganizeOutputDTO> tree = new ArrayList<>();
        for (OrganizeOutputDTO dto : list) {
            if (id.equals(dto.getParentId())) {
                tree.add(dto);
                dto.setChildren(createTree(dto.getId(), list));
            }
        }
        return tree;
    }

    //递归查找
    private List<OrganizeOutputDTO> findTree(Long pid, List<OrganizeOutputDTO> list, List<OrganizeOutputDTO> target) {
        for (OrganizeOutputDTO dto : list) {
            if (pid.equals(dto.getParentId())) {
                target.add(dto);
                findTree(dto.getId(), list, target);
            }
        }
        return target;
    }

}
